package com.farm.view.service.impl;

import com.farm.view.domain.ViewConvertor;
import com.farm.view.domain.ViewDoc;
import com.farm.view.domain.ViewFileModel;
import com.farm.view.domain.ViewRegular;
import com.farm.view.domain.ViewTask;
import com.farm.view.model.ViewFileModelInter;
import com.farm.view.model.ViewFileModels;
import com.farm.view.model.utils.HtmlFileHandles;
import com.farm.core.time.TimeTool;
import com.farm.file.domain.FileBase;
import com.farm.file.domain.FileText;
import com.farm.file.exception.FileNotExistException;
import com.farm.file.service.FileBaseServiceInter;
import com.farm.file.service.FileTextServiceInter;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import com.farm.view.convertor.FileConvertorInter;
import com.farm.view.convertor.FileConvertors;
import com.farm.view.dao.ViewTaskDaoInter;
import com.farm.view.service.ViewConvertorServiceInter;
import com.farm.view.service.ViewDocServiceInter;
import com.farm.view.service.ViewFileModelServiceInter;
import com.farm.view.service.ViewLogServiceInter;
import com.farm.view.service.ViewRegularServiceInter;
import com.farm.view.service.ViewTaskServiceInter;
import com.farm.view.task.domain.ConvertAbleTask;
import com.farm.view.task.domain.ConvertTaskFile;
import com.farm.core.sql.query.DBRule;
import com.farm.core.sql.query.DBRuleList;
import com.farm.core.sql.query.DBSort;
import com.farm.core.sql.query.DataQuery;
import com.farm.core.sql.result.DataResult;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.FileNotFoundException;
import java.sql.SQLException;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;

import javax.annotation.Resource;
import com.farm.core.auth.domain.LoginUser;

/* *
 *功能：转换任务服务层实现类
 *详细：
 *
 *版本：v0.1
 *作者：FarmCode代码工程
 *日期：20150707114057
 *说明：
 */
@Service
public class ViewTaskServiceImpl implements ViewTaskServiceInter {
	@Resource
	private ViewTaskDaoInter viewtaskDaoImpl;
	@Resource
	private ViewRegularServiceInter viewRegularServiceImpl;
	@Resource
	private ViewLogServiceInter viewLogServiceImpl;
	@Resource
	private FileBaseServiceInter fileBaseServiceImpl;
	@Resource
	private ViewDocServiceInter viewDocServiceImpl;
	@Resource
	private ViewConvertorServiceInter viewConvertorServiceImpl;
	@Resource
	private ViewFileModelServiceInter viewModelServiceImpl;
	@Resource
	private FileTextServiceInter fileTextServiceImpl;
	// 當前内存任務隊列
	private static Queue<Map<String, Object>> RAM_TASK_QUEUE = new LinkedList<Map<String, Object>>();

	private static final Logger log = Logger.getLogger(ViewTaskServiceImpl.class);

	@Override
	@Transactional
	public ViewTask insertViewtaskEntity(ViewTask entity, LoginUser user) {
		// TODO 自动生成代码,修改后请去除本注释
		// entity.setCuser(user.getId());
		// entity.setCtime(TimeTool.getTimeDate14());
		// entity.setCusername(user.getName());
		// entity.setEuser(user.getId());
		// entity.setEusername(user.getName());
		// entity.setEtime(TimeTool.getTimeDate14());
		// entity.setPstate("1");
		return viewtaskDaoImpl.insertEntity(entity);
	}

	@Override
	@Transactional
	public ViewTask editViewtaskEntity(ViewTask entity, LoginUser user) {
		// TODO 自动生成代码,修改后请去除本注释
		ViewTask entity2 = viewtaskDaoImpl.getEntity(entity.getId());
		// entity2.setEuser(user.getId());
		// entity2.setEusername(user.getName());
		// entity2.setEtime(TimeTool.getTimeDate14());
		entity2.setFileid(entity.getFileid());
		entity2.setStime(entity.getStime());
		entity2.setEtime(entity.getEtime());
		entity2.setConvertorid(entity.getConvertorid());
		entity2.setViewdocid(entity.getViewdocid());
		entity2.setPcontent(entity.getPcontent());
		entity2.setPstate(entity.getPstate());
		entity2.setCuser(entity.getCuser());
		entity2.setCusername(entity.getCusername());
		entity2.setCtime(entity.getCtime());
		entity2.setId(entity.getId());
		viewtaskDaoImpl.editEntity(entity2);
		return entity2;
	}

	@Override
	@Transactional
	public void deleteViewtaskEntity(String id, LoginUser user) {
		viewtaskDaoImpl.deleteEntity(viewtaskDaoImpl.getEntity(id));
		viewLogServiceImpl.deleteLogsByTaskId(id);
	}

	@Override
	@Transactional
	public ViewTask getViewtaskEntity(String id) {
		// TODO 自动生成代码,修改后请去除本注释
		if (id == null) {
			return null;
		}
		return viewtaskDaoImpl.getEntity(id);
	}

	@Override
	@Transactional
	public DataQuery createViewtaskSimpleQuery(DataQuery query) {
		DataQuery dbQuery = DataQuery.init(query,
				"WDAP_VIEW_TASK a left join WDAP_VIEW_CONVERTOR b on a.CONVERTORID = b.id left join WDAP_FILE c on c.id=a.fileid left join WDAP_VIEW_FILEMODEL d on b.TMODELID =d.id",
				"A.ID AS ID,A.BEFORETASK as BEFORETASK,B.TITLE AS BTITLE,C.TITLE AS CTITLE,d.TITLE as DTITLE,A.FILEID AS FILEID,A.STIME AS STIME,A.ETIME AS ETIME,A.CONVERTORID AS CONVERTORID,A.VIEWDOCID AS VIEWDOCID,A.PCONTENT AS PCONTENT,A.PSTATE AS PSTATE,A.CUSER AS CUSER,A.CUSERNAME AS CUSERNAME,A.CTIME AS CTIME");

		dbQuery.addDefaultSort(new DBSort("A.CTIME", "desc"));
		return dbQuery;
	}

	@Override
	@Transactional
	public void reLoadFileViewTask(String fileid, String userId, String userName) {
		{
			// 检查文件状态
			FileBase filebase = fileBaseServiceImpl.getFilebaseEntity(fileid);
			if (filebase == null) {
				// 文件不存在
				throw new FileNotExistException("the file is not exist:fileid=" + fileid);
			}
			if (!filebase.getPstate().equals("1") && !filebase.getPstate().equals("2")) {
				// 文件不是持久化状态
				throw new FileNotExistException("the file state error!file state is " + filebase.getPstate());
			}
		}
		{
			// 作废队列中的等待任务
			List<ViewTask> waitingTasks = viewtaskDaoImpl
					.selectEntitys(DBRuleList.getInstance().add(new DBRule("FILEID", fileid, "=")).toList());
			for (ViewTask task : waitingTasks) {
				task.setPstate("4");// 禁用
				task.setViewdocid(null);
				viewtaskDaoImpl.editEntity(task);
			}
			// 作废预览文件
			viewDocServiceImpl.deleteViewdocsByFileId(fileid, userId, userName);
		}
		// ------------------------
		{
			// 再重新创建新任务
			List<ViewRegular> regulars = viewRegularServiceImpl.getFileRegular(fileid);
			Collections.sort(regulars, new Comparator<ViewRegular>() {
				@Override
				public int compare(ViewRegular o1, ViewRegular o2) {
					return o1.getSort() - o2.getSort();
				}
			});
			String lastTaskid = null;
			for (ViewRegular regular : regulars) {
				ViewTask task = new ViewTask();
				if (lastTaskid != null && regular.getSort() > 0) {
					task.setBeforetask(lastTaskid);
				}
				task.setConvertorid(regular.getConvertorid());
				task.setFileid(fileid);
				task.setPstate("0");
				task.setViewis(regular.getViewis());
				task.setOuttimenum(regular.getOuttimenum());
				task.setCuser(userId);
				task.setCusername(userName);
				task.setCtime(TimeTool.getTimeDate14());
				task = viewtaskDaoImpl.insertEntity(task);
				lastTaskid = task.getId();
				viewLogServiceImpl.insertViewlog(task.getId(), "创建任务-加入队列 ");
			}
		}
	}

	@Override
	@Transactional
	public ConvertAbleTask getNewRunableTask() throws SQLException {
		// 查询前100条可执行任务
		if (RAM_TASK_QUEUE.size() <= 0) {
			List<Map<String, Object>> resultList = viewtaskDaoImpl.getNewRunableTask();
			log.debug("从数据库加载任务队列...");
			RAM_TASK_QUEUE.addAll(resultList);
		}
		// 获得任务超时时间,获得任务id,获得原文件名称,获得原文件模型名称,获得目标文件模型名称,获得一个转换器,获得原文件模型,获得目标文件模型
		while (!RAM_TASK_QUEUE.isEmpty()) {
			Map<String, Object> node = RAM_TASK_QUEUE.poll();
			try {
				// 如果任務沒有依賴，直接傳出
				if (node.get("BEFORETASK") == null) {
					return getConvertAbleTask(node);
				}
				if (node.get("BEFORETASK") != null) {
					ViewTask beforeTask = getViewtaskEntity(node.get("BEFORETASK").toString());
					// 如果有依賴檢查依賴
					if (beforeTask.getPstate().equals("0") || beforeTask.getPstate().equals("1")) {
						// 依賴等待或執行中則跳過任務
						continue;
					}
					if (beforeTask.getPstate().equals("2")) {
						// 依賴完成，傳出
						return getConvertAbleTask(node);
					}
					if (beforeTask.getPstate().equals("3") || beforeTask.getPstate().equals("4")) {
						// 依賴錯誤或禁用則當前任務報錯並跳過
						throw new RuntimeException("依赖任务无法正常执行");
					}
				}
			} catch (Exception e) {
				log.error(e);
				submitTaskFail(node.get("TASKID").toString(), e.getMessage());
				continue;
			}
		}
		return null;
	}

	/**
	 * 将可用预览任务数据库对象转换为bean对象
	 * 
	 * @param node
	 *            数据库单条记录
	 * @return
	 */
	private ConvertAbleTask getConvertAbleTask(Map<String, Object> node) {
		FileBase fileBase = fileBaseServiceImpl.getFilebaseEntity(node.get("FILEID").toString());
		String filePath = fileBaseServiceImpl.getFileRealPath(node.get("FILEID").toString());
		// ---------------------------------------------------------------------------------------
		ConvertAbleTask task = new ConvertAbleTask();
		FileConvertorInter convertor = FileConvertors.getConvertor(node.get("CLASSKEY").toString());
		if (convertor == null) {
			throw new RuntimeException("the convert " + node.get("CLASSKEY").toString() + " not exist by ["
					+ FileConvertors.getAllConvertorKeys() + "]");
		}
		task.setFileConvertor(convertor);
		task.setFileInfo(new ConvertTaskFile(filePath, fileBase.getTitle(), fileBase.getExname()));
		task.setOutTime(Long.valueOf(node.get("OUTTIMENUM").toString()));
		task.setTaskId(node.get("TASKID").toString());
		task.setoModelTitle(node.get("OTITLE").toString());
		task.settModelTitle(node.get("TTITLE").toString());
		task.setTviewFileModel(ViewFileModels.getModel(node.get("TKEY").toString()));
		task.setOviewFileModel(ViewFileModels.getModel(node.get("OKEY").toString()));
		return task;
	}

	@Override
	@Transactional
	public void submitTaskSuccess(String taskId) {
		// 改寫任务状态
		ViewTask task = viewtaskDaoImpl.getEntity(taskId);
		task.setPstate("2");
		task.setEtime(TimeTool.getTimeDate14());
		// -------------------------------------------------
		// 创建预览文件记录
		ViewConvertor convertor = viewConvertorServiceImpl.getViewconvertorEntity(task.getConvertorid());
		ViewDoc viewDoc = new ViewDoc();
		viewDoc.setFileid(task.getFileid());
		viewDoc.setModelid(convertor.getTmodelid());
		viewDoc.setPstate("2");
		viewDoc.setViewis(task.getViewis());
		viewDoc.setWebpath("NONE");
		viewDoc = viewDocServiceImpl.insertViewdoc(viewDoc);
		// -----------------------------------------------
		task.setViewdocid(viewDoc.getId());
		viewtaskDaoImpl.editEntity(task);
		viewLogServiceImpl.insertViewlog(task.getId(), "转换完成 ");
		// html文件资源重新绑定
		HtmlFileHandle(viewDoc);
		textGetHandle(viewDoc);
	}

	/**
	 * html资源处理（在预览文件任务转换完成后，改写html文件中的资源）
	 * 
	 * @param viewDoc
	 */
	private void HtmlFileHandle(ViewDoc viewDoc) {
		ViewFileModel model = viewModelServiceImpl.getViewmodelEntity(viewDoc.getModelid());
		FileBase filebase = fileBaseServiceImpl.getFilebaseEntity(viewDoc.getFileid());
		ViewFileModelInter modelInter = ViewFileModels.getModel(model.getModelkey());
		// 改写预览文件中html文件的资源地址
		if (modelInter.getExname(filebase.getExname()).toUpperCase().equals("HTML")) {
			File htmlfile = fileBaseServiceImpl.getFile(filebase);
			// 先重写图片
			HtmlFileHandles.reBindImgs(modelInter.getModelFile(htmlfile, filebase.getExname()), viewDoc.getId());
			// 再更新样式
			HtmlFileHandles.bindHtmlStyle(modelInter.getModelFile(htmlfile, filebase.getExname()), filebase.getTitle());
		}
	}

	/**
	 * 抓取附件文本内容处理（在预览文件任务转换完成后，抓取附件的文字内容）
	 * 
	 * @param viewDoc
	 */
	private void textGetHandle(ViewDoc viewDoc) {
		ViewFileModel model = viewModelServiceImpl.getViewmodelEntity(viewDoc.getModelid());
		FileBase filebase = fileBaseServiceImpl.getFilebaseEntity(viewDoc.getFileid());
		ViewFileModelInter modelInter = ViewFileModels.getModel(model.getModelkey());
		FileText fileText = fileTextServiceImpl.getFiletextByFileId(viewDoc.getFileid());
		if (modelInter.isGetTextAble(filebase.getExname()) && !fileText.getCompleteis().equals("1")) {
			File modelFile = modelInter.getModelFile(fileBaseServiceImpl.getFile(filebase), filebase.getExname());
			String text = modelInter.getText(modelFile);
			if (text.length() > 501000) {
				text = text.substring(0, 500000);
			}
			fileText.setFiletext(text.replaceAll("[\\ud800\\udc00-\\udbff\\udfff\\ud800-\\udfff]", ""));
			if (!StringUtils.isBlank(fileText.getFiletext())) {
				fileText.setPcontent(modelInter.getTitle());
				fileText.setCompleteis("1");
				fileTextServiceImpl.editFiletextEntity(fileText, null);
			}
		}
	}

	@Override
	@Transactional
	public void submitTaskFail(String taskId, String message) {
		ViewTask task = viewtaskDaoImpl.getEntity(taskId);
		task.setPstate("3");
		task.setEtime(TimeTool.getTimeDate14());
		viewtaskDaoImpl.editEntity(task);
		if (message.length() > 500) {
			message = message.substring(0, 500);
		}
		viewLogServiceImpl.insertViewlog(task.getId(), "转换错误：" + message);
	}

	@Override
	@Transactional
	public void doTaskHandle(String taskId) {
		ViewTask task = getViewtaskEntity(taskId);
		task.setPstate("1");
		task.setStime(TimeTool.getTimeDate14());
		viewtaskDaoImpl.editEntity(task);
		viewLogServiceImpl.insertViewlog(task.getId(), "开始转换 ");
	}

	@Override
	@Transactional
	public List<Map<String, Object>> getTasksByFileid(String fileid) {
		DataQuery dbQuery = DataQuery.getInstance(1,
				"A.ID AS ID,A.BEFORETASK as BEFORETASK,B.TITLE AS BTITLE,C.TITLE AS CTITLE,d.TITLE as DTITLE,A.FILEID AS FILEID,A.STIME AS STIME,A.ETIME AS ETIME,A.CONVERTORID AS CONVERTORID,A.VIEWDOCID AS VIEWDOCID,A.PCONTENT AS PCONTENT,A.PSTATE AS PSTATE,A.PSTATE as STATETITLE,A.CUSER AS CUSER,A.CUSERNAME AS CUSERNAME,A.CTIME AS CTIME",
				"WDAP_VIEW_TASK a left join WDAP_VIEW_CONVERTOR b on a.CONVERTORID = b.id left join WDAP_FILE c on c.id=a.fileid left join WDAP_VIEW_FILEMODEL d on b.TMODELID =d.id");
		dbQuery.addDefaultSort(new DBSort("A.CTIME", "desc"));
		dbQuery.addRule(new DBRule("A.FILEID", fileid, "="));
		dbQuery.addRule(new DBRule("A.PSTATE", "4", "!="));
		dbQuery.setPagesize(20);
		dbQuery.setNoCount();
		try {
			DataResult result = dbQuery.search();
			result.runDictionary("0:等待,1:执行,2:完成,3:错误,4:禁用", "STATETITLE");
			result.runDictionary(
					"0:<span class='lableDefault'>等待</span>,1:<span class='labelWarn'>执行</span>,2:<span class='labelSuccess'>完成</span>,3:<span class='labelError'>错误</span>,4:<span class='labelError'>禁用</span>",
					"STATETITLE");
			result.runformatTime("CTIME", "yyyy-MM-dd HH:mm:ss");
			return result.getResultList();
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
	}
}
